home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Workbench Add-On
/
Workbench Add-On - Volume 1.iso
/
Dev
/
Amiga-E
/
E_v3.2a
/
Src
/
Utils
/
D.e
< prev
next >
Wrap
Text File
|
1992-09-02
|
11KB
|
298 lines
/* recursive directory tool
needs v37.
Universal directory lister. called with no arguments, by just typing
"d", it lists the current directory. template:
DIR,REC/S,WIDTH/K/N,COL/K/N,SIZE/S,NOSORT/S,NOFILES/S,NODIRS/S,FULL/S,NOANSI/S,
TARGET/K,DO/K/F
DIR specifies an optional path to the dir you wish to list.
may contain standard wildcard patterns like #?~[]%() etc.
REC specifies that subdirectories should be listed recursively.
WIDTH <num> max width of one line of output. if not present, D will
infer this from the current width of the console.
NOTE: currently it just takes WIDTH=77 as default. does anyone
have code that gets the width from the console?
COL <num> where n=1..10, by default, D will try and fit as many
columns as allowed by WIDTH.
SIZE reports the size of each dir as it is being listed. note that
combined with REC gives sizes of whole dir (sub-)trees.
NOSORT by default, dirs are sorted before display. disable this with
the NOSORT switch.
NOFILES displays just dirs
NODIRS displays just files
FULL lists full path instead of just filename
NOANSI doesn't use ansi display codes while printing
TARGET <dir> specifies a target directory for use with DO. should
end in either "/" or ":"
DO <comline> specifies a commandline for automatic script generation.
note that this uses up the rest of D's commandline.
something should be said on the script feature: it enables you
to perform repetitive tasks on whole dirs, or dir-trees. existing
utilities that enabled you to do such tasks where mostly not
flexible enough; d enables you to use the REC keyword in combination
with scripts, allows for variable extensions: use <file>.o if
the original name was <file>.s, and the spec. of a target:
resulting files from the operation are placed in another dir, which
can be a complete mirror image of another dir-tree. makedir
statements are inserted if target: is empty.
following format codes may be used in <commandline>:
%s is file (filename+path)
%f is file WITHOUT extension
%r is file without extension, but with leading <dir> replaced by
<target> (usefull if <commandline> allows for an outputfile)
%> or %< %>> etc. prevents the shell from thinking ">" is a redirection
for D, instead of <commandline>
a complex example:
you wish to have a complete ascii reference of the emodules:
directory, recursively, and with the resulting .txt files
as a mirror-image directory structure somewhere else.
1> D >ram:script emodules: REC TARGET=t:mods/ DO showmodule %>%r.txt %s
1> execute ram:script
will do that for you.
for any file like "emodules:exec/io.m" D will make a line like:
"showmodule >t:mods/exec/io.txt emodules:exec/io.m"
other examples: D >mydirlist dh0: WIDTH=100 SIZE REC NOANSI
D docs: DO type >prt: %s
D asm: TARGET=obj: DO genam %s -o%r.o
D emodules: REC TARGET=ram: DO showmodule %>%r.txt %s
*/
OPT OSVERSION=37
CONST MAXPATH=250
ENUM ER_NONE,ER_BADARGS,ER_MEM,ER_UTIL,ER_ITARG,ER_COML
ENUM ARG_DIR,ARG_REC,ARG_WIDTH,ARG_COL,ARG_SIZE,ARG_NOSORT,ARG_NOFILES,
ARG_NODIRS,ARG_FULL,ARG_NOANSI,ARG_TARGET,ARG_COMMAND,NUMARGS
MODULE 'dos/dosasl', 'dos/dos', 'utility', 'intuition/intuitionbase',
'intuition/intuition', 'graphics/gfxbase', 'graphics/text'
RAISE ER_MEM IF New()=NIL, /* set common exceptions: */
ER_MEM IF String()=NIL, /* every call to these functions will be */
ERROR_BREAK IF CtrlC()=TRUE /* automatically checked against NIL, */
/* and the exception ER_MEM is raised */
DEF dir,command,target,
recf=FALSE,col=3,calccolf=TRUE,comf=FALSE,sizef=FALSE,sortf=TRUE,filesf=TRUE,
fullf=FALSE,ansif=TRUE,dirsf=TRUE,dirw[100]:STRING,
rdargs=NIL,work[250]:STRING,work2[250]:STRING,dirno=0,
prtab[25]:LIST,prcopy[25]:LIST,workdir[250]:STRING,
consolewidth=0
PROC main() HANDLE
DEF args[NUMARGS]:LIST,templ,x,lock,fib:fileinfoblock,s
IF (utilitybase:=OpenLibrary('utility.library',37))=NIL THEN Raise(ER_UTIL)
FOR x:=0 TO NUMARGS-1 DO args[x]:=0
templ:='DIR,REC/S,WIDTH/K/N,COL/K/N,SIZE/S,NOSORT/S,NOFILES/S,NODIRS/S,' +
'FULL/S,NOANSI/S,TARGET/K,DO/K/F'
rdargs:=ReadArgs(templ,args,NIL)
IF rdargs=NIL THEN Raise(ER_BADARGS) /* initialise flags */
IF args[ARG_SIZE] THEN sizef:=TRUE /* from command line args */
consolewidth:=Bounds(IF args[ARG_WIDTH] THEN Long(args[ARG_WIDTH]) ELSE findconsolewidth(),1,1000)
IF args[ARG_COL] THEN (calccolf:=FALSE) BUT col:=Long(args[ARG_COL])
col:=Bounds(col,1,100)
IF args[ARG_NOSORT] THEN sortf:=FALSE
IF args[ARG_NOANSI] THEN ansif:=FALSE
IF args[ARG_NOFILES] THEN filesf:=FALSE
IF args[ARG_NODIRS] THEN dirsf:=FALSE
IF args[ARG_REC] THEN recf:=TRUE
IF args[ARG_FULL] THEN fullf:=TRUE
target:=args[ARG_TARGET]
command:=args[ARG_COMMAND]
IF command THEN comf:=TRUE
IF target
x:=target+StrLen(target)-1
IF (x<target) OR ((x[]<>":") AND (x[]<>"/")) THEN Raise(ER_ITARG)
ENDIF
IF comf
sortf:=FALSE /* read and convert commandline for scripts */
col:=1
filesf:=FALSE
dirsf:=FALSE
IF command[]=0 THEN Raise(ER_COML)
s:=command
WHILE x:=s[]++
IF x="%"
x:=s[]
SELECT x
CASE "s"; ListAdd(prtab,[1],1) /* %s = fullpath */
CASE "f"; ListAdd(prtab,NEW [work],1); s[]:="s" /* %f = work */
CASE "r"; ListAdd(prtab,NEW [work2],1); s[]:="s" /* %r = work2 */
DEFAULT; s[-1]:=" "
ENDSELECT
ENDIF
ENDWHILE
ENDIF
dir:=args[ARG_DIR]
IF dir THEN StrCopy(dirw,dir,ALL)
lock:=Lock(dirw,-2)
IF lock /* if yes, the prob. dir, else wildcard */
IF Examine(lock,fib) AND (fib.direntrytype>0)
AddPart(dirw,'#?',100)
ENDIF
UnLock(lock)
ENDIF
recdir(dirw)
Raise(ER_NONE)
EXCEPT
IF rdargs THEN FreeArgs(rdargs)
IF utilitybase THEN CloseLibrary(utilitybase)
SELECT exception
CASE ER_BADARGS; PrintF('Bad Arguments for D!\n')
CASE ER_MEM; PrintF('No mem!\n')
CASE ER_COML; PrintF('No commandline specified\n')
CASE ER_ITARG; PrintF('Illegal target\n')
CASE ER_UTIL; PrintF('Could not open "utility.library" v37\n')
CASE ERROR_BREAK; PrintF('User terminated D\n')
CASE ERROR_BUFFER_OVERFLOW; PrintF('Internal error\n')
DEFAULT; PrintFault(exception,'Dos Error')
ENDSELECT
ENDPROC
PROC recdir(dirr) HANDLE
DEF er,i:PTR TO fileinfoblock,size=0,anchor=NIL:PTR TO anchorpath,fullpath,
flist=NIL,first,entries=0,ascii,w,x,y,z,flist2=NIL,
isfirst=0,maxfilename=1,maxfilesize=-1,lcol
anchor:=New(SIZEOF anchorpath+MAXPATH)
anchor.breakbits:=4096
anchor.strlen:=MAXPATH-1
er:=MatchFirst(dirr,anchor) /* collect all strings */
WHILE er=0
fullpath:=anchor+SIZEOF anchorpath
i:=anchor.info
ascii:=IF fullf THEN fullpath ELSE i.filename
IF i.direntrytype>0
StringF(work,'\s\l\s[30] ',IF ansif THEN '\e' ELSE '',ascii)
ELSE
StringF(work,'\l\s[30] \r\d[8]',ascii,i.size)
IF i.size>maxfilesize THEN maxfilesize:=i.size
ENDIF
x:=StrLen(ascii)
IF x>maxfilename THEN maxfilename:=x
IF IF i.direntrytype>0 THEN dirsf ELSE filesf
first:=String(EstrLen(work))
StrCopy(first,work,ALL)
flist:=Link(first,flist)
INC entries
ENDIF
IF i.direntrytype<0 THEN size:=size+i.size
IF (i.direntrytype<0) AND comf /* execute commandline */
ListCopy(prcopy,prtab,ALL)
IF comf THEN MapList({x},prcopy,prcopy,`IF x=1 THEN fullpath ELSE x)
StrCopy(work,fullpath,ALL)
x:=InStr(work,'.',0)
IF x<>-1 THEN SetStr(work,x) /* find f% */
IF target
StrCopy(work2,target,ALL)
x:=work; y:=dirw /* was dirr */
WHILE x[]++=y[]++ DO NOP
DEC x
StrAdd(work2,x,ALL) /* find r% */
ELSE
StrCopy(work2,work,ALL)
ENDIF
IF isfirst++=0
StrCopy(workdir,work2,ALL) /* see if makedir is needed */
SetStr(workdir,PathPart(work2)-work2)
x:=Lock(workdir,-2)
IF x THEN UnLock(x) ELSE PrintF('makedir \s\n',workdir)
ENDIF
Flush(stdout); VfPrintf(stdout,command,prcopy); Flush(stdout)
PrintF('\n')
ENDIF
IF recf AND (i.direntrytype>0) /* do recursion(=tail) */
x:=StrLen(fullpath)
IF x+5<MAXPATH THEN CopyMem('/#?',fullpath+x,4)
size:=size+recdir(fullpath)
fullpath[x]:=0
ENDIF
er:=MatchNext(anchor)
ENDWHILE
IF er<>ERROR_NO_MORE_ENTRIES THEN Raise(er)
MatchEnd(anchor)
Dispose(anchor)
anchor:=NIL
maxfilesize:=IF maxfilesize>=0 THEN sillylog10(maxfilesize) ELSE 0
lcol:=Bounds(IF calccolf THEN consolewidth+1/(maxfilesize+maxfilename+2) ELSE col,1,100)
flist:=Link(String(1),flist)
IF entries>2 AND sortf THEN flist:=sort(flist)
IF comf=FALSE /* display dir */
IF dirno THEN PrintF('\n')
PrintF(IF ansif THEN '\e[1mDirectory of: "\s"\e[0m\n' ELSE 'Directory of: "\s"\n',dirr)
ENDIF
first:=flist
x:=entries/lcol /* put dirlist in columns */
IF x*lcol<entries THEN INC x
FOR z:=1 TO x
first:=Next(first)
flist2:=first
FOR y:=1 TO lcol
IF flist2
w:=maxfilename
IF flist2[]="\e"
flist2[w+1]:=0
IF ansif THEN PutStr('\e[1;32m')
PrintF('\s \s',flist2+1,flist2+40-maxfilesize)
IF ansif THEN PutStr('\e[0;31m')
ELSE
flist2[w]:=0
PrintF('\s \s',flist2,flist2+39-maxfilesize)
ENDIF
flist2:=Forward(flist2,x)
IF y<>lcol THEN PrintF(' ')
ENDIF
ENDFOR
PrintF('\n')
CtrlC()
ENDFOR
IF sizef THEN PrintF('BYTE SIZE: \d\n',size)
DisposeLink(flist)
INC dirno
EXCEPT /* nested exception handlers! */
IF anchor THEN MatchEnd(anchor)
Raise(exception) /* this way, we call _all_ handlers in the recursion */
ENDPROC size /* and thus calling MatchEnd() on all hanging anchors */
PROC sort(flist)
DEF sortdone,prev,first,next,nnext
REPEAT
sortdone:=TRUE /* sort dirlist */
prev:=first:=flist
WHILE first:=Next(first)
IF next:=Next(first)
IF Stricmp(first,next)>0
nnext:=Next(next)
Link(prev,first:=Link(next,Link(first,nnext)))
sortdone:=FALSE
ENDIF
ENDIF
prev:=first
ENDWHILE
CtrlC()
UNTIL sortdone
ENDPROC flist
PROC findconsolewidth()
DEF ib:PTR TO intuitionbase,gb:PTR TO gfxbase,w,fw
ib:=intuitionbase
gb:=gfxbase
Forbid()
w:=ib.activewindow.width
fw:=gb.defaultfont.xsize
Permit()
ENDPROC Bounds(w-24/fw,5,250)
PROC sillylog10(n) IS IF n<10 THEN 1 ELSE sillylog10(Div(n,10))+1